package cn.yu_lu.utils;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * 数据加密工具类
 * @author zhang
 *
 */
public class EncryptUtil {
	
	/**
	 * 创建指定算法规范的密钥
	 * @param algorithm 算法名称
	 * @return 密钥对象,当传入空的算法名称时返回null
	 * @throws 当传入的算法名称不存在时抛出
	 */
	public static SecretKey createSecretKey(String algorithm){
		if(JudgeUtil.isBlank(algorithm)) return null;
		KeyGenerator keyGenerator=null;
		try {
			keyGenerator=KeyGenerator.getInstance(algorithm);
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalArgumentException();
		}
		return keyGenerator.generateKey();
	}
	
	/**
	 * 创建指定算法规范的密钥对
	 * @param algorithm 算法名称
	 * @return 密钥对对象,当传入空的算法名称时返回null
	 * @throws 当传入的算法名称不存在时抛出
	 */
	public static KeyPair createKeyPair(String algorithm){
		if(JudgeUtil.isBlank(algorithm)) return null;
		KeyPairGenerator keyPairGenerator=null;
		try {
			keyPairGenerator=KeyPairGenerator.getInstance(algorithm);
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalArgumentException();
		}
		return keyPairGenerator.generateKeyPair();
	}
	
	/**
	 * 对称加密,解密
	 * @param str 待加密(解密)字符串
	 * @param key 密钥
	 * @param mode 操作模式(加密|解密)
	 * @param algorithm 算法名称
	 * @return 加密(解密)结果,当传入空的数据字符串或密钥为空或算法名称为空时返回null
	 * @throws 当传入非法的密钥或操作模式或算法名称时抛出
	 */
	public static String encrypt(String str,String key,int mode,String algorithm){
		if(JudgeUtil.hasBlank(str,key,algorithm)) return null;
		if(mode!=Cipher.ENCRYPT_MODE&&mode!=Cipher.DECRYPT_MODE) throw new IllegalArgumentException();;
		Cipher cipher=null;
		try {
			cipher=Cipher.getInstance(algorithm);
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalArgumentException();
		} catch (NoSuchPaddingException e) {
			throw new IllegalArgumentException();
		}
		try {
			cipher.init(mode,new SecretKeySpec(ConvertUtil.hex2Bytes(key),cipher.getAlgorithm()),new SecureRandom());
		} catch (InvalidKeyException e) {
			throw new IllegalArgumentException();
		}
		try {
			if(Cipher.ENCRYPT_MODE==mode){
				return ConvertUtil.toHex(cipher.doFinal(str.getBytes("UTF-8")));
			}else if(Cipher.DECRYPT_MODE==mode){
				return new String(cipher.doFinal(ConvertUtil.hex2Bytes(str)),"UTF-8");
			}else{
				throw new IllegalArgumentException();
			}
		} catch (IllegalBlockSizeException e) {
			throw new IllegalArgumentException();
		} catch (BadPaddingException e) {
			throw new IllegalArgumentException();
		} catch (UnsupportedEncodingException e) {
			throw new UnsupportedOperationException();
		}
	}
	
	/**
	 * 对称加密
	 * @param str 待加密字符串
	 * @param key 密钥
	 * @param algorithm 算法名称
	 * @return 加密结果字符串,当传入空数据或密钥为空或算法名称为空时返回null
	 */
	public static String encode(String str,String key,String algorithm){
		if(JudgeUtil.hasBlank(str,key,algorithm)) return null;
		return encrypt(str,key,Cipher.ENCRYPT_MODE,algorithm);
	}
	
	/**
	 * 对称解密
	 * @param str 待解密字符串
	 * @param key 密钥
	 * @param algorithm 算法名称
	 * @return 解密结果字符串,当传入空数据或密钥为空或算法名称为空时返回null
	 */
	public static String decode(String str,String key,String algorithm){
		if(JudgeUtil.hasBlank(str,key,algorithm)) return null;
		return encrypt(str,key,Cipher.DECRYPT_MODE,algorithm);
	}

	/**
	 * AES加密
	 * @param str 待加密字符串
	 * @param key 密钥
	 * @return 加密结果，当传入空字符串或密钥为空时返回null
	 */
	public static String aesEncode(String str,String key){
		if(JudgeUtil.hasBlank(str,key)) return null;
		return encode(str,key,"AES");
	}
	
	/**
	 * AES解密
	 * @param str 待解密字符串
	 * @param key 密钥
	 * @return 解密结果，当传入空字符串或密钥为空时返回null
	 */
	public static String aesDecode(String str,String key){
		if(JudgeUtil.hasBlank(str,key)) return null;
		return decode(str,key,"AES");
	}
	
	/**
	 * DES加密
	 * @param str 待加密字符串
	 * @param key 密钥
	 * @return 加密结果，当传入空字符串或密钥为空时返回null
	 */
	public static String desEncode(String str,String key){
		if(JudgeUtil.hasBlank(str,key)) return null;
		return encode(str,key,"DES");
	}
	
	/**
	 * DES解密
	 * @param str 待解密字符串
	 * @param key 密钥
	 * @return 解密结果，当传入空字符串或密钥为空时返回null
	 */
	public static String desDecode(String str,String key){
		if(JudgeUtil.hasBlank(str,key)) return null;
		return decode(str,key,"DES");
	}
	
	/**
	 * DESede(三重DES)加密
	 * @param str 待加密字符串
	 * @param key 密钥
	 * @return 加密结果，当传入空字符串或密钥为空时返回null
	 */
	public static String desedeEncode(String str,String key){
		if(JudgeUtil.hasBlank(str,key)) return null;
		return encode(str,key,"DESede");
	}
	
	/**
	 * DESede(三重DES)解密
	 * @param str 待解密字符串
	 * @param key 密钥
	 * @return 解密结果，当传入空字符串或密钥为空时返回null
	 */
	public static String desedeDecode(String str,String key){
		if(JudgeUtil.hasBlank(str,key)) return null;
		return decode(str,key,"DESede");
	}
	
	/**
	 * RSA加密(解密)【公钥加密的数据用私钥解密，私钥加密的数据用公钥解密】
	 * @param str 待加密（解密）字符串
	 * @param key 密钥
	 * @param mode 操作类型（加密|解密）
	 * @param keyType 密钥类型（公钥|私钥）
	 * @return 加密（解密）结果字符串,当传入空字符串或密钥为空时返回null
	 * @throws 当传入非法的操作类型或密钥类型时抛出
	 */
	public static String rsa(String str,String key,int mode,int keyType){
		if(JudgeUtil.hasBlank(str,key)) return null;
		if(mode!=Cipher.ENCRYPT_MODE&&mode!=Cipher.DECRYPT_MODE) throw new IllegalArgumentException();
		if(keyType!=Cipher.PUBLIC_KEY&&keyType!=Cipher.PRIVATE_KEY) throw new IllegalArgumentException();
		KeyFactory keyFactory=null;
		try {
			keyFactory=KeyFactory.getInstance("RSA");
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalArgumentException();
		}
		Cipher cipher=null;
		try {
			cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalArgumentException();
		} catch (NoSuchPaddingException e) {
			throw new IllegalArgumentException();
		}
		Key useKey=null;
		try {
			if(Cipher.PUBLIC_KEY==keyType){
				X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(ConvertUtil.hex2Bytes(key));
				useKey=keyFactory.generatePublic(x509KeySpec);
			}else if(Cipher.PRIVATE_KEY==keyType){
				PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(ConvertUtil.hex2Bytes(key));
				useKey=keyFactory.generatePrivate(pkcs8KeySpec);
			}else{
				throw new IllegalArgumentException();
			}
		} catch (InvalidKeySpecException e) {
			throw new IllegalArgumentException();
		}
		try {
			cipher.init(mode,useKey,new SecureRandom());
		} catch (InvalidKeyException e) {
			throw new IllegalArgumentException();
		}
		try {
			if(Cipher.ENCRYPT_MODE==mode){
				return ConvertUtil.toHex(cipher.doFinal(str.getBytes("UTF-8")));
			}else if(Cipher.DECRYPT_MODE==mode){
				return new String(cipher.doFinal(ConvertUtil.hex2Bytes(str)),"UTF-8");
			}else{
				throw new IllegalArgumentException();
			}
		} catch (IllegalBlockSizeException e) {
			throw new IllegalArgumentException();
		} catch (BadPaddingException e) {
			throw new IllegalArgumentException();
		} catch (UnsupportedEncodingException e) {
			throw new UnsupportedOperationException();
		}
	}
	
	/**
	 * RSA公钥加密
	 * @param str 待加密字符串
	 * @param key 密钥
	 * @return 加密结果，当传入空字符串或密钥为空时返回null
	 */
	public static String rsaPublicEncode(String str,String key){
		if(JudgeUtil.hasBlank(str,key)) return null;
		return rsa(str,key,Cipher.ENCRYPT_MODE,Cipher.PUBLIC_KEY);
	}
	
	/**
	 * RSA私钥加密
	 * @param str 待加密字符串
	 * @param key 密钥
	 * @return 加密结果，当传入空字符串或密钥为空时返回null
	 */
	public static String rsaPrivateEncode(String str,String key){
		if(JudgeUtil.hasBlank(str,key)) return null;
		return rsa(str,key,Cipher.ENCRYPT_MODE,Cipher.PRIVATE_KEY);
	}
	
	/**
	 * RSA公钥解密
	 * @param str 待解密字符串
	 * @param key 密钥
	 * @return 解密结果，当传入空字符串或密钥为空时返回null
	 */
	public static String rsaPublicDecode(String str,String key){
		if(JudgeUtil.hasBlank(str,key)) return null;
		return rsa(str,key,Cipher.DECRYPT_MODE,Cipher.PUBLIC_KEY);
	}
	
	/**
	 * RSA私钥解密
	 * @param str 待解密字符串
	 * @param key 密钥
	 * @return 解密结果，当传入空字符串或密钥为空时返回null
	 */
	public static String rsaPrivateDecode(String str,String key){
		if(JudgeUtil.hasBlank(str,key)) return null;
		return rsa(str,key,Cipher.DECRYPT_MODE,Cipher.PRIVATE_KEY);
	}
}
